import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Optional

import requests
from manim_voiceover.helper import remove_bookmarks
from manim_voiceover.services.base import SpeechService


@dataclass
class TTSConfig:
    """TTS配置数据类"""

    voice_type: str = "BV700_V2_streaming"  # 语音类型
    rate: int = 24000  # 采样率
    encoding: str = "mp3"  # 编码格式
    compression_rate: float = 1.0  # 压缩率
    speed_ratio: float = 1.0  # 语速比例
    volume_ratio: float = 1.0  # 音量比例
    pitch_ratio: float = 1.0  # 音调比例
    emotion: str = "happy"  # 情感
    language: str = "cn"  # 语言


class TTSClient(SpeechService):
    """文本转语音客户端类"""

    def __init__(self, **kwargs):
        """
        初始化TTS客户端

        Args:
            base_url: API基础URL
        """
        SpeechService.__init__(self, **kwargs)
        self.base_url = "https://tiykupfbeoyz.sealoshzh.site/api/v1/text_to_audio"
        self.session = requests.Session()

    def _prepare_request_body(
        self,
        text: str,
        config: Optional[TTSConfig] = None,
        subjects: str = "未知",
        educational_levels: str = "未知",
        version: str = "true",
    ) -> Dict[str, Any]:
        """
        准备请求体

        Args:
            text: 要转换的文本
            config: TTS配置
            subjects: 主题
            educational_levels: 教育水平
            version: 版本

        Returns:
            请求体字典
        """
        if config is None:
            config = TTSConfig()

        return {
            "Subjects": subjects,
            "Educational_Levels": educational_levels,
            "Version": version,
            "Text": text,
            "Response_Type": "ndjson",
            "Req_Params": {
                "audio_model": "doubao",
                "config": {
                    "voice_type": config.voice_type,
                    "rate": config.rate,
                    "encoding": config.encoding,
                    "compression_rate": config.compression_rate,
                    "speed_ratio": config.speed_ratio,
                    "volume_ratio": config.volume_ratio,
                    "pitch_ratio": config.pitch_ratio,
                    "emotion": config.emotion,
                    "language": config.language,
                },
            },
        }

    def text_to_speech(
        self, text: str, output_path: str, config: Optional[TTSConfig] = None, **kwargs
    ) -> bool:
        """
        将文本转换为语音并保存

        Args:
            text: 要转换的文本
            output_path: 输出文件路径
            config: TTS配置
            **kwargs: 其他请求参数

        Returns:
            bool: 是否成功
        """
        try:
            # 准备请求体
            body = self._prepare_request_body(text, config, **kwargs)

            # 发送请求
            response = self.session.post(
                self.base_url,
                json=body,
                stream=True,  # 使用流式传输
            )

            response.raise_for_status()

            # 创建输出目录
            output_path = Path(output_path)
            output_path.parent.mkdir(parents=True, exist_ok=True)

            # 处理 NDJSON 响应
            audio_urls = []
            for line in response.iter_lines():
                if line:
                    try:
                        data = json.loads(line)
                        if (
                            data["code"] in [200, 1000]
                            and "data" in data
                            and "tts" in data["data"]
                        ):
                            audio_urls.append(data["data"]["tts"])
                    except json.JSONDecodeError:
                        continue

            if not audio_urls:
                print("未找到音频URL")
                return False

            # 下载并合并音频文件
            with open(output_path, "wb") as outfile:
                for url in audio_urls:
                    audio_response = self.session.get(url)
                    audio_response.raise_for_status()
                    outfile.write(audio_response.content)

            return True

        except requests.RequestException as e:
            print(f"请求失败: {str(e)}")
            return False
        except IOError as e:
            print(f"文件保存失败: {str(e)}")
            return False

    def generate_from_text(
        self, text: str, cache_dir: str = None, path: str = None, **kwargs
    ) -> dict:
        """
        生成语音并返回结果字典

        Args:
            text: 要转换的文本
            cache_dir: 缓存目录
            path: 输出路径
            **kwargs: 其他参数

        Returns:
            dict: 包含音频信息的字典
        """
        # 移除书签
        input_text = remove_bookmarks(text)

        if cache_dir is None:
            cache_dir = self.cache_dir

        # 准备输入数据
        input_data = {
            "input_text": input_text,
            "config": {
                "format": "mp3",  # 使用mp3格式
                "channels": 1,  # 单声道
                "rate": 24000,  # 采样率
                "chunk": 1024,  # 数据块大小
            },
            "service": "tts",  # 服务类型
        }

        # 检查缓存
        cached_result = self.get_cached_result(input_data, cache_dir)
        if cached_result is not None:
            return cached_result

        # 确定输出路径
        if path is None:
            audio_path = self.get_audio_basename(input_data) + ".mp3"
        else:
            audio_path = path

        # 创建输出目录
        output_path = Path(cache_dir) / audio_path
        output_path.parent.mkdir(parents=True, exist_ok=True)

        # 转换文本为语音
        success = self.text_to_speech(
            text=input_text,
            output_path=str(output_path),
            config=TTSConfig(),  # 使用默认配置
            **kwargs,
        )

        if not success:
            raise Exception("语音生成失败")

        # 返回结果字典
        return {
            "input_text": text,
            "input_data": input_data,
            "original_audio": audio_path,
        }
